﻿using System.Globalization;
using System.Runtime.CompilerServices;

namespace phminarm.algorithm.Health
{

    /// <summary>
    /// 健康评估方法
    /// </summary>
    public class HealthByWeight
    {
        private string weightfilepath;
        private int part_num;//设备部件数量
        private int[] part_index_num;//设备各个部件的指标数量
        private float[][] index_norm;//归一化后的指数
        private byte[][] index_type;//指标类型，包含正向指标、逆向指标和标准指标
        private float[][] index_max;
        private float[][] index_min;
        private float[][] index_std;
        private float[][] weight_part;//部件各个指标的权重
        private float[] weight;//设备各个部件的权重
        private float[] Health_PartF;//各个部件的健康度
        private float HealthF;//设备总体健康度
                              //健康度从高到低：5,4,3,2,1
        public int[] Health_Part { get; private set; }//各个部件的健康度
        public int Health { get; private set; }//设备总体健康度

        public HealthByWeight(string configfilepath)
        {
            weightfilepath = configfilepath;
            readWeight();

        }

        private void SetWeightByEntropy(float[][] data)
        {

        }

        /// <summary>
        /// 计算机组总体健康度和机组组成部分的子健康度
        /// </summary>
        /// <param name="index"></param>
        public void CalcHealthByWeight(float[][] index)
        {
            //1.归一化
            normlize(index);
            //2.计算部件健康度
            for (int i = 0; i < part_num; i++)
            {
                Health_Part[i] = 0;
                for (int j = 0; j < part_index_num[i]; j++)
                {
                    Health_PartF[i] += weight_part[i][j] * index[i][j];
                }
                Health_Part[i] = mapHIRank(Health_PartF[i]);
            }
            //3.计算机组总体健康度
            for (int i = 0; i < weight.Length; i++)
            {
                HealthF += weight[i] * Health_PartF[i];
            }
            Health = mapHIRank(HealthF);
        }

        public void SetWeight(float[][] weight_part, float[] weight)
        {

        }

        private void saveWeight(string configfileurl)
        {

        }

        private void readWeight()
        {
            try
            {
                //读取配置文件
                StreamReader sR = File.OpenText(weightfilepath);
                List<string> list = new List<string>();
                string nextLine;
                while ((nextLine = sR.ReadLine()) != "")
                {
                    list.Add(nextLine);
                }
                sR.Close();
                //初始化成员变量
                if (list.Count % 5 == 0)
                {
                    //初始化
                    part_num = list.Count / 5;
                    Health_Part = new int[part_num];
                    Health_PartF = new float[part_num];
                    weight = new float[part_num];
                    part_index_num = new int[part_num];
                    weight_part = new float[part_num][];
                    index_type = new byte[part_num][];
                    index_max = new float[part_num][];
                    index_min = new float[part_num][];
                    index_std = new float[part_num][];
                    //读取数据
                    for (int i = 0; i < part_num; i++)
                    {
                        //机组部件的权重
                        weight[i] = Convert.ToSingle(list[0 + 5 * i]);
                        //部件参数子权重
                        weight_part[i] = list[2 + 5 * i].Split(',').ToList().Select(x => Convert.ToSingle(x)).ToArray();
                        part_index_num[i] = weight_part[i].Length;
                        //部件参数的类型
                        index_type[i] = list[1 + 5 * i].Split(',').ToList().Select(x => Convert.ToByte(x)).ToArray();
                        //值域范围
                        index_max[i] = list[3 + 5 * i].Split(',')
                                       .Select(x => Convert.ToSingle(x.Replace("[", "").Replace("]", "").Split(' ')[1])).ToArray();
                        index_min[i] = list[3 + 5 * i].Split(',')
                                       .Select(x => Convert.ToSingle(x.Replace("[", "").Replace("]", "").Split(' ')[0])).ToArray();
                        //部件参数的标准值
                        index_std[i] = list[4 + 5 * i].Split(',').ToList().Select(x => Convert.ToSingle(x)).ToArray();
                    }
                }

            }
            catch (Exception)
            {
                throw;
            }
        }

        private int mapHIRank(float hi)
        {
            if (hi > 0.9) return 5;
            if (hi > 0.7) return 4;
            if (hi > 0.5) return 3;
            if (hi > 0.3) return 2;
            return 1;
        }

        private void normlize(float[][] p)
        {
            index_norm = p;
            for (int i = 0; i < p.Length; i++)
            {
                for (int j = 0; j < p[i].Length; j++)
                {
                    index_norm[i][j] = normalization(p[i][j], index_min[i][j], index_max[i][j], index_std[i][j], index_type[i][j]);
                }
            }
        }

        //最小阈值、最大阈值、标准值、实时值、数据指标类型
        //标准化  基于指标类型计算
        private float normalization(float value, float minValue, float maxValue, float standardValue, byte type)
        {
            //标准值指标
            if (type == 3)
            {
                if (minValue <= value && value < standardValue)
                    return (value - minValue) / (standardValue - minValue);
                else if (standardValue <= value && value <= maxValue)
                    return (maxValue - value) / (maxValue - standardValue);
                else
                    return 0.0f;
            }

            // 正向指标(越大越好)
            else if (type == 2)
            {
                float health_value = (value - minValue) / (maxValue - minValue);
                if (health_value > 1)
                    health_value = 1;
                if (health_value < 0)
                    health_value = 0;
                return health_value;
            }

            // 逆向指标(越小越好)
            else if (type == 1)
            {
                float health_value = 1 - (value - minValue) / (maxValue - minValue);
                if (health_value > 1)
                    health_value = 1;
                if (health_value < 0)
                    health_value = 0;
                return health_value;
            }
            else
                return -1;
        }

    }
}

